import markdown
from django.core.cache import caches
from blogsite.settings import logger
from markdown.extensions.toc import TocExtension
from django.shortcuts import render, get_object_or_404
from blog.models import Article, Category, Tag
from django.views.generic import DetailView, ListView
from django.utils.text import slugify
from comments.forms import CommentForm
from django.db.models import Q

# setting cache channel
try:
    cache = caches["redis"]
except:
    cache = caches["default"]


def index(request):
    art_list = Article.objects.all()
    return render(request, 'list.html', locals())


class IndexView(ListView):
    model = Article
    template_name = 'list.html'
    context_object_name = 'art_list'
    paginate_by = 5

    def get_queryset(self):
        return super(IndexView, self).get_queryset().filter(status=0)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        paginator = context.get('paginator')
        page = context.get('page_obj')
        is_paginated = context.get('is_paginated')
        pagination_data = self.pagination_data(paginator, page, is_paginated)
        context.update(pagination_data)
        return context

    @staticmethod
    def pagination_data(paginator, page, is_paginated):
        if not is_paginated:
            return {}

        left = []
        right = []
        left_has_more = False
        right_has_more = False
        first = False
        last = False

        page_number = page.number
        total_pages = paginator.num_pages
        page_range = paginator.page_range

        if page_number == 1:
            right = page_range[page_number:page_number + 2]
            if right[-1] < total_pages - 1:
                right_has_more = True
            if right[-1] < total_pages:
                last = True

        elif page_number == total_pages:
            left = page_range[(page_number - 3) if (page_number - 3) > 0 else 0:page_number - 1]
            if left[0] > 2:
                left_has_more = True
            if left[0] > 1:
                first = True
        else:
            left = page_range[(page_number - 3) if (page_number - 3) > 0 else 0:page_number - 1]
            right = page_range[page_number:page_number + 2]
            if right[-1] < total_pages - 1:
                right_has_more = True
            if right[-1] < total_pages:
                last = True
            if left[0] > 2:
                left_has_more = True
            if left[0] > 1:
                first = True

        data = {
            'left': left,
            'right': right,
            'left_has_more': left_has_more,
            'right_has_more': right_has_more,
            'first': first,
            'last': last,
        }

        return data


class ArticleDetailView(DetailView):
    model = Article
    template_name = 'detail.html'
    context_object_name = 'article'

    def get(self, request, *args, **kwargs):
        """获取文章，若客户端在10分钟内是第一次访问，将访问量加1并添加ip到缓存，缓存失效时间是10分钟"""
        response = super(ArticleDetailView, self).get(request, *args, **kwargs)
        ip = request.META['HTTP_X_FORWARDED_FOR'] if 'HTTP_X_FORWARDED_FOR' in request.META else request.META[
            'REMOTE_ADDR']
        logger.info("{} has access to the {}.html article".format(ip, self.kwargs.get('pk')))
        cache_name = '{}_{}'.format('visited', self.kwargs.get('pk'))
        visited_ip = cache.get(cache_name, [])
        if ip not in visited_ip:
            self.object.view_add()
            visited_ip.append(ip)
            cache.set(cache_name, visited_ip, 10 * 60)  # 10分钟
        return response

    def get_object(self, queryset=None):
        article = super(ArticleDetailView, self).get_object(queryset=None)

        md = markdown.Markdown(extensions=[
            'markdown.extensions.extra',
            'markdown.extensions.codehilite',
            'markdown.extensions.toc',
            'markdown.extensions.fenced_code',
            'markdown.extensions.sane_lists',
            'markdown.extensions.abbr',
            'markdown.extensions.attr_list',
            'markdown.extensions.def_list',
            'markdown.extensions.footnotes',
            'markdown.extensions.smart_strong',
            'markdown.extensions.meta',
            'markdown.extensions.nl2br',
            'markdown.extensions.tables',
            TocExtension(slugify=slugify),
        ])
        article.body = md.convert(article.body)
        article.toc = md.toc
        return article

    def get_context_data(self, **kwargs):
        context = super(ArticleDetailView, self).get_context_data(**kwargs)
        form = CommentForm()
        comment_list = self.object.comment_set.all()
        context.update({'form': form, 'comment_list': comment_list})
        return context


class CategoryView(ListView):
    model = Article
    template_name = 'list.html'
    context_object_name = 'art_list'

    def get_queryset(self):
        cate_id = get_object_or_404(Category, pk=self.kwargs.get('pk'))
        return super(CategoryView, self).get_queryset().filter(category=cate_id, status=0)


class TagView(ListView):
    model = Article
    template_name = 'list.html'
    context_object_name = 'art_list'

    def get_queryset(self):
        tag_id = get_object_or_404(Tag, pk=self.kwargs.get('pk'))
        return super(TagView, self).get_queryset().filter(tags=tag_id, status=0)


class TimeArchiveView(ListView):
    model = Article
    template_name = 'list.html'
    context_object_name = 'art_list'

    def get_queryset(self):
        year = self.kwargs.get('year')
        month = self.kwargs.get('month')
        print('-+-+-+ ', month, year)
        # return super(TimeArchiveView, self).get_queryset().filter(create_time__startswith='{}-{}'.format(year,month))
        return super(TimeArchiveView, self).get_queryset().filter(create_time__year=year,
                                                                  create_time__month=month, status=0)


def search(request):
    q = request.GET.get('q')
    err_msg = ''
    if not q:
        err_msg = '请输入搜索关键字.'
        return render(request, 'list.html', {'err_msg': err_msg})
    art_list = Article.objects.filter(Q(title__icontains=q) | Q(body__icontains=q) | Q(excerpt__icontains=q))
    return render(request, 'list.html', {'err_msg': err_msg, 'art_list': art_list})


def about(request):
    return render(request, 'about.html')


def contact(request):
    return render(request, 'contact.html')
